package com.yunquan.ohana.ui.calendar.event.month

import android.app.Application
import androidx.databinding.ObservableArrayList
import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
import com.yunquan.ohana.BR
import com.yunquan.ohana.R
import com.yunquan.ohana.base.bus.event.SingleLiveEvent
import com.yunquan.ohana.base.ui.BaseViewModel
import com.yunquan.ohana.entity.ScheduleModel
import com.yunquan.ohana.entity.SchedulesVo
import com.yunquan.ohana.http.BaseHttp
import com.yunquan.ohana.http.exception.ApiException
import com.yunquan.ohana.http.observer.BaseObserver
import com.yunquan.ohana.http.transformer.CommonTransformer
import com.yunquan.ohana.utils.DateUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.tatarka.bindingcollectionadapter2.ItemBinding
import okhttp3.RequestBody.Companion.toRequestBody
import java.time.DayOfWeek
import java.time.Duration
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
import java.time.temporal.TemporalAdjusters
import java.util.Locale

class EventMonthViewModel(application: Application) : BaseViewModel(application) {

    val ui = SingleLiveEvent<Int>()

    val items = ObservableArrayList<EventMonthItemViewModel>()
    val itemBinding = ItemBinding.of<EventMonthItemViewModel>(
        BR.eventMonthItemViewModel,
        R.layout.item_event_month_base,
    )

    var mDeviceId: String? = null
    var mUserType: Boolean = false

    var mCurrentDateTime: LocalDateTime? = null
    var mStartDate: LocalDateTime? = null
    var mEndDate: LocalDateTime? = null

    val format: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.ENGLISH)

    fun initView() {
        viewModelScope.launch(Dispatchers.IO) {
            val showList = mutableListOf<EventMonthItemViewModel>()
            var current = mStartDate!!
            while (!current.isAfter(mEndDate)) {
                val day = current.format(format)
                showList.add(
                    EventMonthItemViewModel(
                        this@EventMonthViewModel,
                        day,
                        mCurrentDateTime!!,
                        emptyList()
                    )
                )
                current = current.plusDays(1)
            }
            withContext(Dispatchers.Main) {
                items.clear()
                items.addAll(showList)
                ui.value = 0
            }
        }
    }

    fun getEventData(
        scheduleId: String? = null,
        roleIds: List<String>? = null,
        status: Int? = null,
        title: String? = null,
    ) {
        val startEpoch = mStartDate!!.atZone(ZoneId.systemDefault()).toEpochSecond()
        val endEpoch = mEndDate!!.atZone(ZoneId.systemDefault()).toEpochSecond()

        val params = SchedulesVo(
            deviceId = mDeviceId,
            startTime = startEpoch.toString(),
            endTime = endEpoch.toString(),
            roleIds = roleIds,
            status = status,
            scheduleId = scheduleId,
            title = title
        )
        showLoading()
        val body = Gson().toJson(params).toRequestBody(BaseHttp.MEDIA_TYPE_JSON)
        BaseHttp.api.getAllSchedulesByDeviceId(body)
            .compose(CommonTransformer())
            .subscribe(object : BaseObserver<List<ScheduleModel>>() {
                override fun onSuccess(result: List<ScheduleModel>?) {
                    super.onSuccess(result)
                    if (result != null) {
                        setShowData(result)
                    } else {
                        hideLoading()
                    }
                }

                override fun onError(e: ApiException) {
                    super.onError(e)
                    hideLoading()
                }
            })
    }


    fun setShowData(data: List<ScheduleModel>) {
        viewModelScope.launch(Dispatchers.IO) {
            val showMap = mutableMapOf<String, MutableList<ScheduleModel>>()
            for (e in data) {
                setEveryDayEvent(e, showMap)
            }
            withContext(Dispatchers.Main) {
                hideLoading()
                items.forEach { item ->
                    val list = showMap[item.date]?.map {
                        EventMonthChildItemViewModel(
                            this@EventMonthViewModel,
                            it
                        )
                    }?.toList()
                    if (list?.isNotEmpty() == true) {
                        item.setData(mCurrentDateTime!!, list)
                    } else {
                        item.setData(mCurrentDateTime!!, emptyList())
                    }
                }
            }
        }
    }

    private fun setEveryDayEvent(
        e: ScheduleModel,
        showMap: MutableMap<String, MutableList<ScheduleModel>>
    ) {
        val zone = ZoneId.systemDefault()
        val startLdt = LocalDateTime.ofInstant(Instant.ofEpochSecond(e.startTime!!.toLong()), zone)
        val endLdt = LocalDateTime.ofInstant(Instant.ofEpochSecond(e.endTime!!.toLong()), zone)

        val dayFormatter =
            DateTimeFormatter.ofPattern(DateUtils.FORMAT.DATE_HORIZONTAL, Locale.ENGLISH)
        val startDay = startLdt.toLocalDate().format(dayFormatter)
        val endDay = endLdt.toLocalDate().format(dayFormatter)

        e.startDate = startDay
        e.endDate = endDay
        if (startDay == endDay) {
            val timeFormatter12 = DateTimeFormatter.ofPattern("hh:mm a", Locale.ENGLISH)
            e.startTimeStr = startLdt.format(timeFormatter12)
            e.endTimeStr = endLdt.format(timeFormatter12)
            showMap.getOrPut(startDay) { mutableListOf() }.add(e)
        } else {
            val dayDiff = ChronoUnit.DAYS.between(startLdt.toLocalDate(), endLdt.toLocalDate()) + 1
            val timeFormatter24 = DateTimeFormatter.ofPattern("HH:mm a", Locale.ENGLISH)
            for (i in 0 until dayDiff.toInt()) {
                val bean = e.copy()
                val dayDate = startLdt.toLocalDate().plusDays(i.toLong())
                val day = dayDate.format(dayFormatter)

                when (day) {
                    startDay -> {
                        // 第一天，开始时间到23:59:59
                        bean.startTimeStr = startLdt.format(timeFormatter24)
                        bean.endTimeStr = "23:59 PM"
                    }

                    endDay -> {
                        // 最后一天，00:00:00到结束时间
                        bean.startTimeStr = "00:00 AM"
                        bean.endTimeStr = endLdt.format(timeFormatter24)
                    }

                    else -> {
                        // 中间天，00:00:00到23:59:59
                        bean.startTimeStr = "00:00 AM"
                        bean.endTimeStr = "23:59 PM"
                    }
                }
                showMap.getOrPut(day) { mutableListOf() }.add(bean)
            }
        }
    }
}